// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <memory>
#include <string>
#include <unordered_map>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/binance_base/api_util/auth_key.h"
#include "coin2/exchange/order/binance.pb.h"

namespace coin2::exchange::binance_futures::api_order {

class BinanceFuturesNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::BinanceFuturesRestParams;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);

 public:
  explicit BinanceFuturesNativePrivateClient(
      const MarketExchangeApi& mea,
      const order::OrderConnectionConfig& config,
      bool is_delivery);

  std::shared_ptr<AsioHttpContext> QueryAccountBalanceAndAccountPosition(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryCrossMargin(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOpenOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryAllOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryTrades(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryTransfer(const std::string& asset);
  std::shared_ptr<AsioHttpContext> QueryFundingFee();
  std::shared_ptr<AsioHttpContext> PlaceSingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceBatchOrders(const std::vector<RestParams>& params);
  std::shared_ptr<AsioHttpContext> CancelSingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelBatchOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> GenListenKey(bool is_init);
  std::shared_ptr<AsioHttpContext> ExtendListenKey();
  std::shared_ptr<AsioHttpContext> DeleteListenKey();

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;
  std::string GetCurrMilliseconds() const {
    return std::to_string(GetCurrentTimestamp() / 1000000);
  }

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);

  void Prepare() override;
  std::string DebugString() const;
  BaseRestAuth* GetAuth() const override;

 private:
  void SetBindIp(const std::string&);

 private:
  std::string account_path_;
  std::string open_orders_path_;
  std::string query_fill_path_;
  std::string history_orders_path_;
  std::string query_transfer_path_;
  std::string query_funding_fee_path_;
  std::string place_single_order_path_;
  std::string place_batch_orders_path_;
  std::string listen_path_;
  bool is_delivery_;

  // handle api limit
  int64_t start_time_{0};
  std::string listen_key_;
  std::unordered_map<std::string, int32_t> api_block_info_;
  std::unordered_map<std::string, int32_t> api_req_info_;

  RoundRobinRestAuth margin_auths_;  // for portfolio margin trading
};

}  // namespace coin2::exchange::binance_futures::api_order
